package cn.zhfeat.hatch.web.service.impl.system;


import cn.zhfeat.core.base.BaseResultModel;
import cn.zhfeat.core.base.ResultStatus;
import cn.zhfeat.core.shiro.ShiroSessionData;
import cn.zhfeat.core.shiro.bean.ShiroSysAuthorityBean;
import cn.zhfeat.framework.shiro.util.ShiroSerializeUtil;
import cn.zhfeat.hatch.dto.company.CompanyDepartmentDto;
import cn.zhfeat.hatch.dto.company.CompanyInfoDto;
import cn.zhfeat.hatch.dto.store.BaseStoreInfoDto;
import cn.zhfeat.hatch.dto.store.BaseStoreToUserDto;
import cn.zhfeat.hatch.dto.sysuser.SysAuthorityDto;
import cn.zhfeat.hatch.dto.sysuser.SysRoleAuthorityDto;
import cn.zhfeat.hatch.dto.sysuser.SysUserDto;
import cn.zhfeat.hatch.dto.sysuser.SysUserRoleDto;
import cn.zhfeat.hatch.entity.company.CompanyDepartment;
import cn.zhfeat.hatch.entity.company.CompanyInfo;
import cn.zhfeat.hatch.entity.store.BaseStoreInfo;
import cn.zhfeat.hatch.entity.store.BaseStoreToUser;
import cn.zhfeat.hatch.entity.sysuser.SysRoleAuthority;
import cn.zhfeat.hatch.entity.sysuser.SysUser;
import cn.zhfeat.hatch.entity.sysuser.SysUserRole;
import cn.zhfeat.hatch.rpc.*;
import cn.zhfeat.hatch.web.service.ILoginService;
import cn.zhfeat.hatch.web.utils.AESUtil;
import cn.zhfeat.hatch.web.utils.ConfigUtil;
import cn.zhfeat.hatch.web.utils.ShiroSessionDataUtil;
import cn.zhfeat.utils.MD5Util;
import cn.zhfeat.utils.StringUtils;
import cn.zhfeat.utils.cache.CacheUtility;
import com.alibaba.fastjson.JSON;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @description: 用户登录接口实现层
 *
 * @author ZhangHao
 * @date 2018年5月17日 下午3:54:01 
 * @version 1.0.0.1
 */
@Service("loginService")
public class LoginServiceImpl implements ILoginService {

	@Autowired
	private IAccountRpcService accountRpcService;

	@Autowired
	private IBaseStoreInfoRpcService baseStoreInfoRpcService;

	@Autowired
	private IRoleRpcService roleRpcService;
	
	@Autowired
	private IDepartmentRpcService departmentRpcService;

	@Autowired
    private CacheUtility cacheUtility;

    @Autowired
    private ICompanyInfoRpcService companyInfoRpcService;

	private final Logger log = LoggerFactory.getLogger(this.getClass());
	
	
    /** 缓存类别*/
    private String categoryKey = "Shiro-Session";
    /** 缓存功能*/
    private String cacheKey = "User-Info";    
    /** 自定义缓存key*/
    private String redisCacheListKey = "User-Session-Id-";
    /** 缓存类别*/
    private String categoryAuthKey = "Shiro-Session";  
    /** 缓存功能*/
    private String cacheAuthKey = "Permissions-Cache";     
    /** 自定义缓存key*/
    private String redisCacheListAuthKey = "Shiro-System-UserId-";

	/** 缓存类别 免登规则*/
	private String ExemptCategoryKey = "Exempt-Login";
	/** 缓存功能 免登规则*/
	private String ExemptcacheKey = "Login-Count";

	/**
	 * @description: 用户通过用户名密码登录
	 *
	 * @param dto
	 * @return 
	 * @author ZhangHao
	 * @date 2018年5月17日 下午3:48:39 
	 * @version 1.0.0.1
	 */
	@Override
	public BaseResultModel ajaxLogin(SysUserDto dto) {
		BaseResultModel baseResultModel = new BaseResultModel();
		
		//如果用户名或密码为空，返回异常提示
        if (StringUtils.isBlank(dto.getAccount()) || StringUtils.isBlank(dto.getPwd())) {
        	if(!"login_code".equals(dto.getCodeType())) {
            	baseResultModel.setStatus(ResultStatus.REQUEST_PARAM_ERROR.getStatusCode());
            	baseResultModel.setMessage(ResultStatus.REQUEST_PARAM_ERROR.getStatusMessage());
                return baseResultModel;
        	}
        }
        
        try {
        //首先根据手机号查询用户，用于判断该用户是否注册过
        SysUser user = accountRpcService.findUserInfoByType(dto);
        
        if (user == null) {
        	baseResultModel.setStatus(ResultStatus.HTTP_REQUEST_ERROR.getStatusCode());
        	baseResultModel.setMessage("尚未注册,请先注册");
            return baseResultModel;
        }
        
        //用户账户
        String account = dto.getAccount();
        //用户密码
        String pwd = "";
        //如果是验证码登录，从数据库中查询是否有该用户，如果没有，返回该用户不存在，如果有，则使用数据库中该用户的密码进行登录
        if("login_code".equals(dto.getCodeType())) {
        	pwd = user.getPwd();
        }else {
            pwd = dto.getPwd();
            //密码二次加密
            pwd = MD5Util.encodeString(MD5Util.encodeString(pwd) + ConfigUtil.MD5_PWD_STR);
        }

        //判断是否删除
        Integer isDeleted = user.getIsDeleted();
        if (isDeleted == 1) {
            //被删除的账户
      	    baseResultModel.setStatus(ResultStatus.HTTP_REQUEST_ERROR.getStatusCode());
      		baseResultModel.setMessage("账号已被删除，如果有问题请联系管理员");
            return baseResultModel;
        }
        
        //判断用户是否有密码
        String pwdword = user.getPwd();
        if (StringUtils.isBlank(pwdword)) {
      	    baseResultModel.setStatus("2");
      	    baseResultModel.setMessage("请使用短信验证登陆");
            return baseResultModel;
        }
        
        //判断是否停用
        Integer status = user.getStatus();
        if (status != 0) {
      	    baseResultModel.setStatus(ResultStatus.HTTP_REQUEST_ERROR.getStatusCode());
      	    baseResultModel.setMessage("该账号为失效状态，如果有问题请联系管理员");
            return baseResultModel;
        }
        
        /** 后登录的用户把之前登录的用户的会话信息及权限信息从缓存中清除，实现踢出*/
        //KickOutTheOnlineUser(user.getThirdToken(),String.valueOf(user.getId()));
        
        Subject subject = SecurityUtils.getSubject();
        AuthenticationToken authenticationtoken = new UsernamePasswordToken(account, pwd);
        //使用shiro进行登录认证 
        subject.login(authenticationtoken);
        //获取所有权限
        
        /** 获取用户登录后创建的登录会话*/
        Session session = subject.getSession();
        
        /** 定义失效日期**/
        Long timeout = 24 * 60 * 60 * 1000l;
        
        /** 设置session失效时间，为1天*/
        session.setTimeout(timeout);
        
        /** 获取sessionId*/
        String sessionId = session.getId().toString();
        SysUser suEntity = new SysUser();
        suEntity.setId(user.getId());
        suEntity.setThirdToken(sessionId);
        suEntity.setUpdateTime(new Date());
        Long nowTime = new Date().getTime();
        suEntity.setThirdTokenExpiryTime(new Date(timeout + nowTime));
        /** 更新用户的sessionId 以及失效时间**/
        accountRpcService.updateSelective(suEntity);
        
        /** 设置与用户绑定的登录信息*/
        ShiroSessionData shiroSessionData = new ShiroSessionData();

        
        //设置用户id
        shiroSessionData.setUserId(user.getId());
        
        //设置用户企业id
        shiroSessionData.setCid(user.getCid());
        
        //设置用户的id
        shiroSessionData.setUserId(user.getId());
        
        //设置用户的名称
        shiroSessionData.setUserName(user.getName());
        
        //设置用户的手机号
        shiroSessionData.setUserAccount(user.getAccount());
        
        //设置用户选择协议的状态
        shiroSessionData.setAgreement(user.getAgreement());
        
        //设置用户的身份标识
        if(user.getUserIdentity() == 1 || user.getUserIdentity() == 3) {
        	//如果是个人及个人无归属数据，设置业务身份标识为1(个人)
        	shiroSessionData.setDataIdentity(1);
        }else if(user.getUserIdentity() == 2 || user.getUserIdentity() == 4) {
        	//如果是管理及管理无归属数据，设置业务身份标识为2(管理)
        	shiroSessionData.setDataIdentity(2);
        }

        
        dto.setId(user.getId());
        dto.setCid(user.getCid());
        List<SysUser> attributeLists = accountRpcService.findUserAttributeByDto(dto);
        for(int i=0;i<attributeLists.size();i++) {
        	if("store".equals(attributeLists.get(i).getAttributeName())) {
     
                //如果有无归属数据
                if(user.getUserIdentity() == 3 || user.getUserIdentity() == 4) {
                	//如果用户选择的一组门店不为null
                	if(attributeLists.get(i).getAttributeValue() != null && !"".equals(attributeLists.get(i).getAttributeValue())) {
                		shiroSessionData.setResponsibleStoreIds(attributeLists.get(i).getAttributeValue() + "," + "0");
                	}else {
                		 //设置用户对应的一组负责门店
                        shiroSessionData.setResponsibleStoreIds("0");
                	}
                }else {
                	shiroSessionData.setResponsibleStoreIds(attributeLists.get(i).getAttributeValue());
                }
                //判断用户是否含有无归属权限
        	}else if("department".equals(attributeLists.get(i).getAttributeName())) {
        		
                //如果有无归属数据
                if(user.getUserIdentity() == 3 || user.getUserIdentity() == 4) {
                	//如果用户选择的一组部门不为null
                	if(attributeLists.get(i).getAttributeValue() != null && !"".equals(attributeLists.get(i).getAttributeValue())) {
                		shiroSessionData.setResponsibleDepartmentIds(attributeLists.get(i).getAttributeValue() + "," + "0");
                	}else {
                		 //设置用户对应的一组负责部门
                        shiroSessionData.setResponsibleDepartmentIds("0");
                	}
                }else {
                	shiroSessionData.setResponsibleDepartmentIds(attributeLists.get(i).getAttributeValue());
                }
        	}
        }
       
        //设置用户所属门店id、名称
        BaseStoreToUserDto baseStoreToUserDto = new BaseStoreToUserDto();
        baseStoreToUserDto.setCid(user.getCid());
        baseStoreToUserDto.setUserId(user.getId());
        List<BaseStoreToUser> btus = accountRpcService.selectUserStores(baseStoreToUserDto);
        BaseStoreInfo btu = new BaseStoreInfo();
        if(btus != null && btus.size() > 0) {
        	BaseStoreInfoDto baseStoreInfoDto = new BaseStoreInfoDto();
        	baseStoreInfoDto.setCid(user.getCid());
        	baseStoreInfoDto.setId(btus.get(0).getStoreId());
        	btu = baseStoreInfoRpcService.findEntityByType(baseStoreInfoDto);
        }
        if(btu != null) {
        shiroSessionData.setBelongStoreId(btu.getId());
        shiroSessionData.setBelongStoreName(btu.getName());
        }
        //设置用户所属部门id、名称
        shiroSessionData.setBelongDepartmentId(user.getDepartmentId());
        CompanyDepartmentDto companyDepartmentDto = new CompanyDepartmentDto();
        companyDepartmentDto.setId(user.getDepartmentId());
        CompanyDepartment companyDepartment = departmentRpcService.getCompanyDepartment(companyDepartmentDto);
        if(companyDepartment != null) {
        shiroSessionData.setBelongDepartmentName(companyDepartment.getName());
        }
        //设置用户对应的一组菜单权限
		//根据用户ID获取用户的全部角色
		SysUserRoleDto sysUserRoleDto = new SysUserRoleDto();
		sysUserRoleDto.setUserId(user.getId());
		List<SysUserRole> sysUserRoles = accountRpcService.selectSysUserRoles(sysUserRoleDto);
		if(sysUserRoles == null || sysUserRoles.size() == 0) {
      	    baseResultModel.setStatus(ResultStatus.HTTP_REQUEST_ERROR.getStatusCode());
      	    baseResultModel.setMessage("该账号没有角色");
            return baseResultModel;
		}
		
		//shiro英文标识存储集合，这里用list是因为要保持其原有顺序
	    List<String> NameEnList = new ArrayList<String>();
	    
	    String roleNames = "";
		//根据角色获取用户的全部菜单，根据标识去重
		for(int i=0;i<sysUserRoles.size();i++) {	
			SysRoleAuthorityDto sysRoleAuthorityDto = new SysRoleAuthorityDto();
			sysRoleAuthorityDto.setRoleId(sysUserRoles.get(i).getRoleId());
			sysRoleAuthorityDto.setIsDeleted(0);
			List<SysRoleAuthority> s = roleRpcService.findSysRoleAuthorityByDto(sysRoleAuthorityDto);
			for(int o=0;o<s.size();o++) {
				NameEnList.add(s.get(o).getAuthorityNameEn());
			}
			if(i == 0) {
				roleNames += sysUserRoles.get(i).getRoleName();
			}else {
				roleNames += "," + sysUserRoles.get(i).getRoleName();
			}
			
		}

		//去重后的菜单标识
		List<String> newNameEnListr = removeDuplicateWithOrder(NameEnList);
		
		List<ShiroSysAuthorityBean> authsResult = new ArrayList<ShiroSysAuthorityBean>();
		
		//基础菜单
        List<ShiroSysAuthorityBean> auths = accountRpcService.findMenuListByDto(new SysAuthorityDto());
        
        for(int i=0;i<auths.size();i++) {
        	for(int o=0;o<newNameEnListr.size();o++) {
        		if(auths.get(i).getNameEn().equals(newNameEnListr.get(o))) {
        			authsResult.add(auths.get(i));
        			continue;
        		}
        	}
        }
        
        //设置用户对应的一组角色权限名称
        shiroSessionData.setRoleNames(roleNames);

        
        //增加菜单权限
        shiroSessionData.setAuths(authsResult);


        //根据cid查询公司详细信息，用于判断该公司是否进行了微信授权
        CompanyInfoDto companyInfoDto = new CompanyInfoDto();
        companyInfoDto.setId(user.getCid());
        CompanyInfo companyInfo = companyInfoRpcService.findEntityByType(companyInfoDto);

        //为用户绑定企业微信授权信息
        shiroSessionData.setWechatAuth(companyInfo.getWechatAuth());

        
        /** 将用户绑定信息对象转换成JSON*/
        String shiroSessionDataStr = JSON.toJSONString(shiroSessionData);
        /** 把用户绑定信息放到全局登录会话中进行维护*/
        session.setAttribute("sessionUserData", shiroSessionDataStr);
		log.debug("用户对应的一组负责门店--------------"+ shiroSessionData.getResponsibleStoreIds());
		log.debug("用户对应的一组负责部门--------------"+ shiroSessionData.getResponsibleDepartmentIds());

        //获取初次登陆验证参数
        Integer remarks = user.getIsFirstLogin();
        
        //判断是不是账号的第一次登陆
        if (remarks == 0) {
            //更新首次登陆状态为1
            user.setIsFirstLogin(1);
            //更新用户登录次数
            accountRpcService.updateSelective(user);
            baseResultModel.setStatus("3");
            baseResultModel.setMessage("第一次登陆，确认信息");
            baseResultModel.setData(user.getCid());
            return baseResultModel;
        } else {
      	    baseResultModel.setStatus(ResultStatus.SUCCESS.getStatusCode());
      	    baseResultModel.setMessage(ResultStatus.SUCCESS.getStatusMessage());
      	    baseResultModel.setData(user.getCid());
            return baseResultModel;
        }
          //捕获系统登录失败所产生的异常
        } catch (Exception e) {
        	baseResultModel.setStatus(ResultStatus.HTTP_REQUEST_ERROR.getStatusCode());
        	baseResultModel.setMessage("密码错误");
        	// 打印登录异常日志
            e.printStackTrace();
        	return baseResultModel;
        }
	}
	
	
	/**
	 * @description: 删除ArrayList中重复元素，保持顺序
	 *
	 * @param list
	 * @return 
	 * @author ZhangHao
	 * @date 2018年5月27日 下午4:45:10 
	 * @version 1.0.0.1
	 */
	 public List<String> removeDuplicateWithOrder(List<String> list) {    
	    Set<String> set = new HashSet<String>();    
	     List<String> newList = new ArrayList<String>();    
	   for (Iterator<String> iter = list.iterator(); iter.hasNext();) {    
	         Object element = iter.next();    
	         if (set.add((String) element))    
	            newList.add((String) element);    
	      }     
	     list.clear();    
	     list.addAll(newList);    
	    return list;    
	 }   

    /**
     * @description: 
     * 首次加载页面时，根据用户点击的一级菜单权限ID，从登陆用户角色对应的所有的权限中匹配其对应的二级菜单和三级菜单
     * @param dto
     * @return 
     * @author ZhangHao
     * @date 2018年5月21日 上午12:47:56 
     * @version 1.0.0.1
     */
	@Override
	public Object ajaxAuthsInfo(SysAuthorityDto dto) {
		
    	BaseResultModel baseResultModel = new BaseResultModel();
    	
    	//获取用户绑定的全部菜单权限
  	    ShiroSessionData shiroSessionData = ShiroSessionDataUtil.getShiroSessionData();
  	    List<ShiroSysAuthorityBean> auths = shiroSessionData.getAuths();
  	    
  	    //用于存储1级菜单对应的2级菜单
  	    List<ShiroSysAuthorityBean> authsChildrenTwo = new ArrayList<ShiroSysAuthorityBean>();
  	    
  	    //拿到全部的2级菜单
        for(int i=0;i<auths.size();i++){
        	if(dto.getId().equals(auths.get(i).getParentCode())){
        		authsChildrenTwo.add(auths.get(i));
        	}
        }
        
        //用于存储2级菜单对应的3级菜单
        List<ShiroSysAuthorityBean> authsChildrenThree = new ArrayList<ShiroSysAuthorityBean>();
        for(int i=0;i<auths.size();i++){
        	for(int o=0;o<authsChildrenTwo.size();o++){
        		if(auths.get(i).getParentCode().equals(authsChildrenTwo.get(o).getId())) {
        			//如果是微信授权菜单，那么在url上拼接一个微信授权标识，用于判断是否有微信授权
        			if(("2").equals(String.valueOf(auths.get(i).getProductId()))){
        				if(shiroSessionData.getWechatAuth() == 0){
							auths.get(i).setUrl(auths.get(i).getUrl() + shiroSessionData.getWechatAuth());
						}
					}
					System.out.println(auths.get(i).getUrl());
        			authsChildrenThree.add(auths.get(i));
        			continue;
        		}
        	}
        }
        //将二级菜单和三级菜单合并，交由前端做菜单逻辑处理
        authsChildrenTwo.addAll(authsChildrenThree);
        
        if(authsChildrenTwo != null && authsChildrenTwo.size() > 0){
        	baseResultModel.setData(authsChildrenTwo);
      	    baseResultModel.setStatus(ResultStatus.SUCCESS.getStatusCode());
      	    baseResultModel.setMessage(ResultStatus.SUCCESS.getStatusMessage());
        }
        
        return baseResultModel;
	}


    /**
     * @description: 退出登陆接口
     *
     * @return 
     * @author ZhangHao
     * @date 2018年5月27日 下午5:56:40 
     * @version 1.0.0.1
     */
	@Override
	public Object ajaxExitLogin() {
    	BaseResultModel baseResultModel = new BaseResultModel();
		//緩存的權限清除
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        //session設置為失效
        Session session = subject.getSession();
        session.setTimeout(0);
  	    baseResultModel.setStatus(ResultStatus.SUCCESS.getStatusCode());
  	    baseResultModel.setMessage(ResultStatus.SUCCESS.getStatusMessage());
  	    return baseResultModel;
	}
	
	
	/**
	 * @description: 踢出指定在线用户
	 * 1、根据userId清除用户对应的一组权限
	 * 2、根据sessionId设置用户登陆会话为失效
	 *
	 * @return 
	 * @author ZhangHao
	 * @date 2018年6月1日 上午11:46:44 
	 * @version 1.0.0.1
	 */
	public Boolean KickOutTheOnlineUser(String sessionId,String userId) {
        Session s = null;
        Boolean killTag = true;
        try {
        	//拿到登陆会话
            s = (Session) ShiroSerializeUtil.deserializeToObject((String) cacheUtility.getCacheDataManager().getStringValue(categoryKey, cacheKey, redisCacheListKey + sessionId));
            //删除该用户在redis中缓存的权限
            cacheUtility.getCacheDataManager().removeValue(categoryAuthKey, cacheAuthKey, redisCacheListAuthKey + userId);
            //删除session登录会话
            cacheUtility.getCacheDataManager().removeValue(categoryKey, cacheKey, redisCacheListKey + sessionId);
        } catch (Exception e) {
        	killTag = false;
            e.printStackTrace();
        }
        return killTag;
	}

	/**
	 * @description: 从redis中判断当前session是否失效
	 *
	 * @param
	 * @author ZhangHao
	 * @date 2018/8/8 13:59
	 * @version 1.0.0.1
	 * @return java.lang.Object
	 */
	@Override
	public Object ajaxGetShiroSession() {
		ShiroSessionData shiroSessionData = ShiroSessionDataUtil.getShiroSessionData();
		BaseResultModel baseResultModel = new BaseResultModel();
		Long userId = shiroSessionData.getUserId();
		String authCache = cacheUtility.getCacheDataManager().getStringValue(categoryAuthKey, cacheAuthKey, redisCacheListAuthKey + userId);
		if(authCache != null){
			baseResultModel.setStatus(ResultStatus.SUCCESS.getStatusCode());
			baseResultModel.setMessage(ResultStatus.SUCCESS.getStatusMessage());
		}else{
			baseResultModel.setStatus(ResultStatus.HTTP_REQUEST_ERROR.getStatusCode());
			baseResultModel.setStatus(ResultStatus.HTTP_REQUEST_ERROR.getStatusMessage());
		}
		return baseResultModel;
	}

	/**
	 * @description: 判断token是否存在，是否过期接口，如果存在且未过期，根据token按规则生成ticket
	 *
	 * @param
	 * @author ZhangHao
	 * @date 2018/8/27 11:30
	 * @version 1.0.0.1
	 * @return java.lang.Object
	 */

    @Override
    public Object validateToken(HttpServletRequest request) {
		//对象参数
		BaseResultModel resultModel = new BaseResultModel();

		SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

		SimpleDateFormat sfDay = new SimpleDateFormat("yyyy-MM-dd");

		String countKey = "count";

		SysUserDto dto = new SysUserDto();
		//根据token获取account、password、exemptsTokenExpiryTime
		dto.setExemptsToken(request.getParameter("exemptsToken"));
        SysUser entity = accountRpcService.findUserInfoByType(dto);

		//将当前日期与token的失效时间进行比对
		Date date = new Date();
		//如果token对应的用户存在且token的失效时间大于当前时间
		if(entity != null){
			String expiryTime = sf.format(entity.getExemptsTokenExpiryTime());

			int i = sf.format(date).compareTo(expiryTime);
			//如果当前日期大于过期时间
			if(i > 0){
				resultModel.setData("");
                resultModel.setStatus(ResultStatus.HTTP_REQUEST_ERROR.getStatusCode());
                resultModel.setMessage("token已过期");
			}else{
				String maxId = cacheUtility.getCacheDataManager().getStringValue(ExemptCategoryKey, ExemptcacheKey,countKey);
				if(maxId == null || "".equals(maxId)){
					//给redis自增序列设置一个初始值
					cacheUtility.getCacheDataManager().putStringValue(ExemptCategoryKey, ExemptcacheKey,countKey, "1");
					maxId = "1";
				}
				//按ASE加密规则生成ticket，在redis中维护一个ticket的自增序列,每次获取该自增序列，根据规则生成ticket
				String ticket = AESUtil.encode(dto.getExemptsToken(),ConfigUtil.THIRD_TOKEN_PASSWORD  + maxId);
				//返回tickt
				resultModel.setData(ticket);
                resultModel.setStatus(ResultStatus.SUCCESS.getStatusCode());
                resultModel.setMessage(ResultStatus.SUCCESS.getStatusMessage());
			}
		}
		return resultModel;
    }

    /**
     * @description: 根据用户名、密码、创建时间生成token，更新数据库(内部使用)
     *
     * @param
     * @author ZhangHao
     * @date 2018/8/27 11:44
     * @version 1.0.0.1
     * @return java.lang.Object
     */

	@Override
	public Object createToken(HttpServletRequest request) {
		//对象参数
		BaseResultModel resultModel = new BaseResultModel();

		SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

		//用户名
		String account =  request.getParameter("account");
		//密码
		String password = request.getParameter("password");
		//过期时间
		String expiryTime = request.getParameter("expiryTime");
		//密码二次加密
		password = MD5Util.encodeString(MD5Util.encodeString(password) + ConfigUtil.MD5_PWD_STR);

		SysUserDto dto = new SysUserDto();
		dto.setAccount(account);
		SysUser user = accountRpcService.findUserInfoByType(dto);

		//如果查询出的用户不为空，并且密码和参数中的密码一致
		if(user != null && user.getPwd().equals(password)){
			//根据用户名查询数据库，根据加密后的密码进行匹配，如果匹配的上，根据用户名生成token
			String token = MD5Util.encodeStringDouble(account);
			//根据account,token,过期时间，更新数据库
			SysUser entity = new SysUser();
			entity.setExemptsToken(token);
			entity.setId(user.getId());
			entity.setUpdateTime(new Date());
			try {
				entity.setExemptsTokenExpiryTime(sf.parse(expiryTime));
			} catch (ParseException e) {
				e.printStackTrace();
			}
			accountRpcService.updateSelective(entity);

			//返回token
			resultModel.setData(token);
			resultModel.setStatus(ResultStatus.SUCCESS.getStatusCode());
			resultModel.setMessage(ResultStatus.SUCCESS.getStatusMessage());
		}else{
			resultModel.setStatus(ResultStatus.HTTP_REQUEST_ERROR.getStatusCode());
			resultModel.setStatus(ResultStatus.HTTP_REQUEST_ERROR.getStatusMessage());
		}
		return resultModel;
	}

	/**
	 * @description:
	 * 根据ticket全局票据，按规则解析成token，根据token从DB拿到用户名密码，
	 * 根据用户名密码进行授权操作。更新token失效时间为当前时间。转发到登陆页面
	 *
	 * @param
	 * @author ZhangHao
	 * @date 2018/8/27 13:19
	 * @version 1.0.0.1
	 * @return org.springframework.web.servlet.ModelAndView
	 */

	@Override
	public ModelAndView validateTicket(HttpServletRequest request) {
		//对象参数
		String ticket = request.getParameter("ticket");
		ModelAndView modelAndView = new ModelAndView();
		SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String countKey = "count";
		String maxId = cacheUtility.getCacheDataManager().getStringValue(ExemptCategoryKey, ExemptcacheKey,countKey);
		try {
			//解密ticket，加上自增序列为token
			String token = AESUtil.decode(ticket,ConfigUtil.THIRD_TOKEN_PASSWORD + maxId);

			//如果entity为null,那么跳转到无权限页面
			if(token == null || "".equals(token)){
				throw new RuntimeException();
			}
			//根据token获取account、password、third_token_expiry_time
			SysUserDto dto = new SysUserDto();
			dto.setExemptsToken(token);
			SysUser entity = accountRpcService.findUserInfoByType(dto);
			//根据token获取用户信息后，将自增序列加1，这样就确保了该ticket只能使用一次
			cacheUtility.getCacheDataManager().incrBy(ExemptCategoryKey, ExemptcacheKey,countKey,1);

			//将当前日期与token的失效时间进行比对
			Date date = new Date();
			String expiryTime = sf.format(entity.getExemptsTokenExpiryTime());
			int i = sf.format(date).compareTo(expiryTime);
			//如果当前日期大于过期时间，直接捕获异常，给用户没有该功能权限的提示
			if(i > 0){
				throw new RuntimeException();
			}
			String account = entity.getAccount();
			String password = entity.getPwd();
			//封装
			SysUserDto loginDto = new SysUserDto();
			loginDto.setAccount(account);
			loginDto.setPwd(password);
			loginDto.setCodeType("login_code");
			ajaxLogin(loginDto);
			//更新该用户对应的token的失效时间为当前时间
//			SysUser entitySys = new SysUser();
//			entitySys.setId(entity.getId());
//			entitySys.setExemptsToken(token);
//			entitySys.setExemptsTokenExpiryTime(date);
//			entitySys.setUpdateTime(new Date());
//			accountRpcService.updateSelective(entitySys);
			modelAndView = toMainPage(request);
		} catch (Exception e) {
			//e.printStackTrace();
			modelAndView = new ModelAndView("403");
			return modelAndView;
		}
		return modelAndView;
	}


	/**
     * @description: 从session中拿到所有的权限url，
     * 用于判断用户返回时当前页面是否是最后一页
     *
     * @return 
     * @author ZhangHao
     * @date 2018年6月2日 上午9:57:45 
     * @version 1.0.0.1
     */
	@Override
	public Object ajaxAuthsUrl() {
    	BaseResultModel baseResultModel = new BaseResultModel();
		ShiroSessionData shiroSessionData = ShiroSessionDataUtil.getShiroSessionData();
		List<ShiroSysAuthorityBean> list = shiroSessionData.getAuths();
		if(list != null && list.size() > 0) {
			baseResultModel.setData(list);
	  	    baseResultModel.setStatus(ResultStatus.SUCCESS.getStatusCode());
	  	    baseResultModel.setMessage(ResultStatus.SUCCESS.getStatusMessage());
		}else {
        	baseResultModel.setStatus(ResultStatus.HTTP_REQUEST_ERROR.getStatusCode());
          	baseResultModel.setStatus(ResultStatus.HTTP_REQUEST_ERROR.getStatusMessage());
		}
		return baseResultModel;
	}


	/**
	 * @description: 获取登录所需要的绑定信息
	 *
	 * @param
	 * @author ZhangHao
	 * @date 2018/8/27 13:33
	 * @version 1.0.0.1
	 * @return org.springframework.web.servlet.ModelAndView
	 */

	public ModelAndView toMainPage(HttpServletRequest httpServletRequest) {
		// 格式化日期，用于计算CRM的签名
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

		ShiroSessionData shiroSessionData = ShiroSessionDataUtil.getShiroSessionData();

		// 从session中拿到登录账号
		String userAccount = shiroSessionData.getUserAccount();

		// 拿到CRM的签名信息
		String sign = MD5Util.encodeString(MD5Util
				.encodeString("api_crm_anPOSCrmGerD4KOO1CO8iTq9WPuT" + simpleDateFormat.format(new Date()) + "login"));

		// 拿到所有菜单以及其对应的url
		List<ShiroSysAuthorityBean> auths = shiroSessionData.getAuths();

		// 拿到用户对应的一组角色权限
		String roleNames = shiroSessionData.getRoleNames();

		// 获取首页URL信息
		String mainPage = "";

		// 标记CRM店员菜单是否存在
		Long crmStaffId = 0l;

		for (ShiroSysAuthorityBean auth : auths) {
			// 取匹配上的第一个三级菜单
			// if(auth.getPermissionLevel() != null && auth.getPermissionLevel() == 3) {
			// mainPage = auth.getUrl();
			// break;
			// }

			// 拿到首页url，用于默认展示
			if ("main_page".equals(auth.getNameEn())) {
				mainPage = auth.getUrl();
			}
			// 标记CRM店员菜单是否存在
			if ("crm_staff_list".equals(auth.getNameEn())) {
				crmStaffId = auth.getId();
			}
		}

		List<ShiroSysAuthorityBean> authsCrm = new ArrayList<ShiroSysAuthorityBean>();
		// 如果是店员，则所有菜单都在店员工作台一级菜单下显示(为CRM特殊处理)
		if (crmStaffId > 0) {
			for (int i = 0; i < auths.size(); i++) {
				// 如果菜单的id与CRM店员菜单id相同
				if (auths.get(i).getId() == crmStaffId) {
					authsCrm.add(auths.get(i));
				}
				// 如果是二级菜单,则将二级菜单的父菜单设置为CRM店员工作台
				if (auths.get(i).getPermissionLevel() != null && auths.get(i).getPermissionLevel() == 2) {
					auths.get(i).setParentCode(crmStaffId);
					authsCrm.add(auths.get(i));
					// 如果是三级菜单,则直接拿到该菜单
				} else if (auths.get(i).getPermissionLevel() != null && auths.get(i).getPermissionLevel() == 3) {
					authsCrm.add(auths.get(i));
				}
			}
			auths = authsCrm;
			shiroSessionData.setAuths(auths);
			// 更新session中的用户绑定信息
			Subject subject = SecurityUtils.getSubject();
			Session session = subject.getSession();
			String shiroSessionDataStr = JSON.toJSONString(shiroSessionData);
			session.setAttribute("sessionUserData", shiroSessionDataStr);
		}

		// 初始化一个ModelAndView
		ModelAndView modelAndView = new ModelAndView("main");
		modelAndView.addObject("sysUser", shiroSessionData);
		modelAndView.addObject("account", userAccount);
		modelAndView.addObject("roleNames", roleNames);
		modelAndView.addObject("sign", sign);
		modelAndView.addObject("auths", auths);
		modelAndView.addObject("main_page", mainPage);

		// 返回前端页面进行渲染
		return modelAndView;
	}

}
